package com.ccf.business.etl.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.common.utils.constant.Constants;
import com.ccf.business.etl.model.Node;
import com.ccf.business.etl.model.vo.RuleSynonymVO;
import com.ccf.business.etl.service.INodeService;
import com.common.model.exception.ServiceException;
import com.common.model.pojo.UserInfo;
import com.common.model.result.CodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.common.model.result.PageResult;
import com.common.model.pojo.Query;
import com.service.mybatis.util.Condition;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.service.mybatis.service.impl.SuperServiceImpl;

import lombok.extern.slf4j.Slf4j;

import com.ccf.business.etl.model.RuleSynonym;
import com.ccf.business.etl.mapper.RuleSynonymMapper;
import com.ccf.business.etl.service.IRuleSynonymService;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 
 *
 * @author zhaoj
 * @date 2021-11-29 10:41:10
 */
@Slf4j
@Service
public class RuleSynonymServiceImpl extends SuperServiceImpl<RuleSynonymMapper, RuleSynonym> implements IRuleSynonymService {

    @Autowired
    private INodeService nodeService;

    /**
    * 列表
    * @param query
    * @return
    */
    @Override
    public PageResult findList(Query query){
        Page<RuleSynonym> page = page(Condition.getPage(query), Condition.getQueryWrapper(query));
        List<RuleSynonymVO> datas = page.getRecords().stream().map(RuleSynonym::toVo).collect(Collectors.toList());
        return PageResult.<RuleSynonymVO>builder().datas(datas).code(CodeEnum.SUCCESS.getCode()).count(page.getTotal()).build();
    }

    @Override
    public boolean importSynonym(MultipartFile file) throws IOException {
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(file.getInputStream(), RuleSynonym.class, new ReadListener<RuleSynonym>() {
            /**
             * 单次缓存的数据量
             */
            public static final int BATCH_COUNT = 500;
            /**
             *临时存储
             */
            private List<RuleSynonym> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

            /**
             * 是否存在数据
             */
            private boolean hasData = false;

            /**
             * 这里会一行行的返回头
             * @param headMap
             * @param context
             */
            @Override
            public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
                log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
                String subject = headMap.get(0).getStringValue();
                String desc = headMap.get(1).getStringValue();
                String synonym = headMap.get(2).getStringValue();

                if(!StrUtil.equals(subject, RuleSynonym.SUBJECT_HEADER_1)  || !StrUtil.equals(desc, RuleSynonym.SUBJECT_HEADER_2)
                || !StrUtil.equals(synonym, RuleSynonym.SUBJECT_HEADER_3)) {
                    throw new ServiceException("导入失败，请选择正确的文件模板进行导入");
                }

                //解析到头部
                hasData = true;
            }


            @Override
            public void invoke(RuleSynonym data, AnalysisContext context) {
                //解析到每行数据
                hasData = true;

                cachedDataList.add(data);
                if (cachedDataList.size() >= BATCH_COUNT) {
                    saveData();
                    // 存储完成清理 list
                    cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
                }
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                if(hasData) {
                    saveData();
                } else {
                    throw new ServiceException("导入失败，请选择正确的文件模板进行导入");
                }
            }

            /**
             * 加上存储数据库
             */
            private void saveData() {
                //过滤空数据
                cachedDataList = cachedDataList.stream().filter(s -> StrUtil.isNotEmpty(s.getSubject())).collect(Collectors.toList());
                if(cachedDataList.size() > 0) {
                    log.info("{}条数据，开始存储数据库！", cachedDataList.size());
                    // 查找库中已经存在的主词
                    List<RuleSynonym> existList = list(Wrappers.<RuleSynonym>lambdaQuery().in(RuleSynonym::getSubject, cachedDataList.stream().map(RuleSynonym::getSubject).collect(Collectors.toList())));
                    Map<String, RuleSynonym> synonymMap = new HashMap<>();
                    if(CollectionUtil.isNotEmpty(existList)) {
                        synonymMap =  existList.stream().collect(Collectors.toMap(RuleSynonym::getSubject, Function.identity()));
                    }

                    //判断是否需要合并同义词
                    for (RuleSynonym synonym : cachedDataList) {
                        RuleSynonym oldSynonym = synonymMap.get(synonym.getSubject());
                        if(ObjectUtil.isNotNull(oldSynonym)) {
                            synonym.setId(oldSynonym.getId());
                            //不为空则导入
                            if(StrUtil.isNotEmpty(synonym.getSynonyms())) {
                                synonym.setSynonyms(oldSynonym.getSynonyms() + Constants.COMMA + synonym.getSynonyms());
                            }
                        }

                        //去重同义词
                        String[] synonyms = StrUtil.split(synonym.getSynonyms(), Constants.COMMA);
                        String result = Stream.of(synonyms).distinct().filter(s -> s.length() < 10).collect(Collectors.joining(Constants.COMMA));
                        synonym.setSynonyms(result);
                        synonym.setCreator(UserInfo.DEFAULT_USER_ID);
                    }

                    saveOrUpdateBatch(cachedDataList);
                    log.info("存储数据库成功！");
                }
            }
        }).sheet().doRead();
        return true;
    }

    @Override
    public boolean deleteValidate(String ids) {
        String[] idArrays = StrUtil.split(ids, Constants.COMMA);

        LambdaQueryWrapper<Node> qw = Wrappers.<Node>lambdaQuery();
        for (String id : idArrays) {
            qw.or().like(Node::getParams, id);
        }
        long count = nodeService.count(qw);
        if(count > 0) {
           return false;
        }

        return true;
    }
}
